﻿using System;
using System.Threading;
using Codeplex;
using Microsoft.SharePoint;

namespace SKN
{
    /// <summary>
    /// Contains common method for Security
    /// </summary>
    public static class Security
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="groupName"></param>
        /// <returns></returns>
        public static SPGroup GetSiteGroup(SPWeb web, string groupName)
        {
            foreach (SPGroup group in web.SiteGroups)
                if (group.Name.ToLower() == groupName.ToLower())
                    return group;

            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <returns></returns>
        public static SPUser GetSiteAdmin(SPWeb web)
        {
            foreach (SPUser user in web.SiteUsers)
                if (user.IsSiteAdmin)
                    return user;

            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <returns></returns>
        public static SPUserCollection GetSiteAdmins(SPWeb web)
        {
            SPUserCollection users = null;

            foreach (SPUser user in web.SiteUsers)
                if (user.IsSiteAdmin)
                    users.Add(user.LoginName, user.Email, user.Name, user.Notes);

            return users;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="newRoleDefinition"></param>
        public static void AddRole(SPWeb web, SPRoleDefinition newRoleDefinition)
        {
            bool isNotFound = true;
            foreach (SPRoleDefinition roleDef in web.RoleDefinitions)
            {
                if (roleDef.Name.Equals(newRoleDefinition.Name))
                {
                    isNotFound = false;
                    break;
                }
            }
            if (isNotFound)
            {
                web.RoleDefinitions.Add(newRoleDefinition);
            }

            web.Update();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="groupName"></param>
        /// <param name="groupOwner"></param>
        /// <param name="groupDescription"></param>
        /// <param name="newRoleDefinition"></param>
        public static void AddGroup(SPWeb web, string groupName, SPUser groupOwner, string groupDescription,
                                    string newRoleDefinition)
        {
            SPGroup oGroup = GetSiteGroup(web, groupName);

            if (oGroup == null)
            {
                web.SiteGroups.Add(groupName, groupOwner, null, groupDescription);
                oGroup = GetSiteGroup(web, groupName);
            }

            // Create the role assignment object
            var oRoleAssignment = new SPRoleAssignment(oGroup);

            // Add the role definition to the role assignemnt. 
            // This will assign the specific permission to the security principal for this role assignemnt.
            oRoleAssignment.RoleDefinitionBindings.Add(web.RoleDefinitions[newRoleDefinition]);

            // Now we need to add the role assignment to the web
            web.RoleAssignments.Add(oRoleAssignment);

            //// Now update the web
            //web.Update();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="groupName"></param>
        public static void RemoveGroup(SPWeb web, string groupName)
        {
            SPGroup oGroup = GetSiteGroup(web, groupName);

            if (oGroup != null)
            {
                web.SiteGroups.Remove(groupName);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="roleName"></param>
        public static void DeleteRole(SPWeb web, string roleName)
        {
            //bool RoleFound = false;
            //foreach (SPRoleDefinition roleDefinition in web.RoleDefinitions)
            //    if (string.Equals(roleDefinition.Name,roleName,StringComparison.InvariantCultureIgnoreCase))
            //    {
            //        RoleFound = true;
            //        break;
            //    }

            //if (RoleFound)
            web.RoleDefinitions.Delete(roleName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="groupName"></param>
        public static void RemoveGroupRoleAssignment(SPWeb web, string groupName)
        {
            SPGroup oGroup = GetSiteGroup(web, groupName);

            if (oGroup != null)
            {
                web.RoleAssignments.Remove(oGroup);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="userName"></param>
        public static void RemoveUserRoleAssignment(SPWeb web, string userName)
        {
            SPUser user = web.AllUsers[userName];

            if (user != null)
            {
                web.RoleAssignments.Remove(user);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="strGroup"></param>
        /// <param name="userLogin"></param>
        /// <param name="strUserName"></param>
        /// <param name="userEmail"></param>
        public static void AddUser(SPWeb web, string strGroup, string userLogin, string strUserName, string userEmail)
        {
            // get site's user collection
            SPUserCollection userColl = web.AllUsers;

            //web.EnsureUser(userLogin);


            // if user exists, throw exception 
            foreach (SPUser user in userColl)
            {
                if (user.LoginName.ToLower() == userLogin.ToLower())
                {
                    throw new Exception("User " + userLogin + " already exists.");
                }
            }
            try
            {
                using (var evelate = new ElevationManager())
                {
                    web.AllUsers.Add(userLogin, userEmail, strUserName, null);

                    // get the user object to assign a role
                    SPUser spUser = web.AllUsers[userLogin];

                    if (!string.IsNullOrEmpty(strGroup) && (null != web.SiteGroups[strGroup]))
                    {
                        //Open group
                        SPGroup spGroup = web.SiteGroups[strGroup];

                        //Add and update group with new user
                        spGroup.AddUser(spUser.LoginName, spUser.Email, spUser.Name, string.Empty);
                        spGroup.Update();
                    }
                    else
                    {
                        // get the reader role
                        SPRoleDefinitionCollection roleDefsColl = web.RoleDefinitions;

                        SPRoleDefinition readRoleDef = null;
                        foreach (SPRoleDefinition roleDef in roleDefsColl)
                        {
                            if (roleDef.Type == SPRoleType.Reader)
                            {
                                readRoleDef = roleDef;
                                break;
                            }
                        }

                        // create a new role assignment for the user
                        var roleAssignment = new SPRoleAssignment(spUser);

                        // elevate permissions to allow new user to be added to the role.

                        // add the user to the role
                        roleAssignment.RoleDefinitionBindings.Add(readRoleDef);

                        // add the role assignment to the site
                        web.RoleAssignments.Add(roleAssignment);
                    }
                    // apply the update.
                    web.Update();
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
            }
        }

        /// <summary>
        /// Use this method to add a new role assignment
        /// </summary>
        /// <param name="web"></param>
        /// <param name="strGroup"></param>
        /// <param name="roleDefinition"></param>
        public static void AddRoleAssignment(SPWeb web, string strGroup, string roleDefinition)
        {
            SPGroup spGroup = web.SiteGroups[strGroup];
            SPRoleDefinition spRoleDefinition = web.RoleDefinitions[roleDefinition];

            var spRoleAssignment = new SPRoleAssignment(spGroup);
            spRoleAssignment.RoleDefinitionBindings.Add(spRoleDefinition);
            web.RoleAssignments.Add(spRoleAssignment);

            web.Update();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="listname"></param>
        /// <param name="strGroup"></param>
        /// <param name="roleDefinition"></param>
        public static void AddListRoleAssignment(SPWeb web, string listname, string strGroup, string roleDefinition)
        {
            SPList list = web.Lists[listname];

            SPGroup spGroup = web.SiteGroups[strGroup];
            SPRoleDefinition spRoleDefinition = web.RoleDefinitions[roleDefinition];
            var spRoleAssignment = new SPRoleAssignment(spGroup);
            spRoleAssignment.RoleDefinitionBindings.Add(spRoleDefinition);
            list.RoleAssignments.Add(spRoleAssignment);
            list.Update();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="web"></param>
        /// <param name="rootwebGroupName"></param>
        /// <param name="roleDefinitionName"></param>
        public static void AddRootWebRoleAssignment(SPWeb web, string rootwebGroupName, string roleDefinitionName)
        {
            using (SPWeb rootWeb = web.Site.RootWeb)
            {
                SPGroup grp = rootWeb.Groups[rootwebGroupName];
                SPRoleDefinition roleDefinition = rootWeb.RoleDefinitions[roleDefinitionName];

                var oRoleAssignment = new SPRoleAssignment(grp);
                oRoleAssignment.RoleDefinitionBindings.Add(roleDefinition);
                web.RoleAssignments.Add(oRoleAssignment);

                web.Update();
            }
        }

        /// <summary>
        /// Use this method to quickly update the default group association
        /// </summary>
        /// <param name="web"></param>
        /// <param name="ownersGroup">Pass the groupname to update or blank to skip</param>
        /// <param name="visitorsGroup">Pass the groupname to update or blank to skip</param>
        /// <param name="membersGroups">Pass the groupname to update or blank to skip</param>
        public static void UpdateSecurityGroups(SPWeb web, string ownersGroup, string membersGroups,
                                                string visitorsGroup)
        {
            //web.Properties["vti_associategroups"] = "1;2;3";
            if (!string.IsNullOrEmpty(ownersGroup))
            {
                web.Properties["vti_associateownergroup"] = GetSiteGroup(web, ownersGroup).ID.ToString();
            }

            if (!string.IsNullOrEmpty(membersGroups))
            {
                web.Properties["vti_associatemembergroup"] = GetSiteGroup(web, membersGroups).ID.ToString();
            }

            if (!string.IsNullOrEmpty(visitorsGroup))
            {
                web.Properties["vti_associatevisitorgroup"] = GetSiteGroup(web, visitorsGroup).ID.ToString();
            }

            web.Properties.Update();
        }


        private static SPGroup EnsureGroup(SPWeb web, string groupName)
        {
            SPGroup group;

            string[] groupQuery = { groupName };
            SPGroupCollection groupsFound = web.SiteGroups.GetCollection(groupQuery);
            if ((groupsFound != null) && (groupsFound.Count == 1) && string.Equals(groupsFound[0].Name,groupName,StringComparison.InvariantCultureIgnoreCase))
            {
                group = groupsFound[0];
            }
            else
            {
                web.SiteGroups.Add(groupName, GetSiteAdmin(web) , null, groupName);
                group = web.SiteGroups[groupName];
                web.Update();
            }

            return group;
        }

        private static SPRoleDefinition EnsureRoleDefinition(SPWeb web, string name, string description, SPBasePermissions permissions)
        {
            bool bRoleDefExist = false; 

            for (int i = 0; i < web.RoleDefinitions.Count; i++)
            {
                if (string.Equals(web.RoleDefinitions[i].Name,name,StringComparison.InvariantCultureIgnoreCase))
                {
                    bRoleDefExist = true;
                    break;
                }
            }
            if (!bRoleDefExist)
            {
                var roleDefinition = new SPRoleDefinition
                                         {
                                             Name = name,
                                             Description = description,
                                             BasePermissions = permissions
                                         };

                web.RoleDefinitions.Add(roleDefinition);
                web.Update();
            }

            return web.RoleDefinitions[name];
        }

       
    }
}